/**
 * Copyright (c) 2010 BullionXpress.com,
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

package com.bullionxpress.server.impl;

import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Vector;
import com.bullionxpress.shared.model.Instrument;
import com.bullionxpress.shared.model.Transaction;
import com.bullionxpress.shared.model.TransactionType;
import com.bullionxpress.shared.service.DuplicateTransactionIDException;
import com.bullionxpress.shared.service.InstrumentDatabase;
import com.bullionxpress.shared.service.InvalidTransactionIDFormatException;
import com.bullionxpress.shared.service.TransactionDatabase;
import com.bullionxpress.shared.service.TransactionNotFoundException;
import com.bullionxpress.shared.util.Log;

public class TransactionManager extends java.rmi.server.UnicastRemoteObject implements TransactionDatabase {

    public TransactionManager() throws RemoteException {
        //What should go in the constructor?
        connect();
    }
    Connection conn = null;
    Statement statement = null;

    public void connect() {

        try {
            conn = DatabaseManager.getConnection();

            try {
                statement = conn.createStatement();
                statement.executeUpdate("CREATE TABLE IF NOT EXISTS transactions (id varchar(16), timestamp long, price double, units long, instrument varchar(32), buyerid varchar(16), sellerid varchar(16), type varchar(32), thedate date)");
            } catch (Exception ex) {
                Log.info(ex);
                ex.printStackTrace();
            }

        } catch (Exception ex) {
            Log.info(ex);
            ex.printStackTrace();
        }
    }

    public Transaction[] getAll() {
        try {
            String query = "SELECT * FROM transactions";
            conn = DatabaseManager.getConnection();
            statement = conn.createStatement();
            ResultSet result = statement.executeQuery(query);
            Vector v = new Vector();
            while (result.next()) {
                String id = result.getString("id");
                //Log.info("Looking up:" + id);
                Transaction transaction = get(id);
                v.addElement(transaction);
            }
            Transaction[] transactionList = new Transaction[v.size()];
            for (int i = 0; i < v.size(); i++) {
                transactionList[i] = (Transaction) v.get(i);
            }
            return transactionList;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public Transaction get(String id) throws TransactionNotFoundException {
        if (id == null) {
            throw new IllegalArgumentException();
        }
        String query = "SELECT * FROM transactions WHERE id = '" + id + "'";
        ResultSet result = null;
        boolean r = false;
        try {
            conn = DatabaseManager.getConnection();
            statement = conn.createStatement();
            result = statement.executeQuery(query);
            r = result.next();
        } catch (Exception ex) {
        }

        if (r) {
            Transaction transaction = new Transaction();
            try {
                String symbol = result.getString("instrument");
                transaction.setId(result.getString("id"));
                transaction.setBuyerId(result.getString("buyerid"));
                transaction.setSellerId(result.getString("sellerid"));
                transaction.setPrice(result.getDouble("price"));
                transaction.setUnits(result.getLong("units"));
                transaction.setDate(result.getDate("thedate"));
                Instrument instrument = new Instrument(symbol);
                transaction.setInstrument(instrument);
                transaction.setTimestamp(result.getLong("timestamp"));
                String value = result.getString("type");
                TransactionType type = TransactionType.UNKNOWN;
                if( value != null ){
                    if( value.equals("TRADE")){
                        type = TransactionType.TRADE;
                    } else if( value.equals("DEPOSIT")){
                        type = TransactionType.DEPOSIT;
                    } else if( value.equals("WITHDRAWAL")){
                        type = TransactionType.WITHDRAWAL;
                    }
                }
                transaction.setType(type);
            } catch(Exception ex){
                ex.printStackTrace();
                throw new TransactionNotFoundException();
            }
            return transaction;
        } else {
            throw new TransactionNotFoundException();
        }
    }

    public void add(Transaction b) throws DuplicateTransactionIDException, InvalidTransactionIDFormatException {

        if (b == null) {
            throw new IllegalArgumentException();
        } else if (b.getId() == null) {
            throw new InvalidTransactionIDFormatException();
        } 

        try {
            Transaction a = get(b.getId());
            throw new DuplicateTransactionIDException();
        } catch(TransactionNotFoundException ex){
            
        }

        String query = "INSERT INTO transactions (id, timestamp, price, units, instrument, buyerid, sellerid, type, thedate)  VALUES ( '" + b.getId() + "', " + b.getTimestamp() + ", " + b.getPrice() + ", " + b.getUnits() + ", '" +b.getInstrument().getSymbol() + "', '" + b.getBuyerId() + "','" + b.getSellerId() + "', '" + b.getType().toString() + "', '" + b.getDate() + "')";
        int n = 0;
        try {
            conn = DatabaseManager.getConnection();
            statement = conn.createStatement();
            n = statement.executeUpdate(query);
        } catch (SQLException ex) {
            ex.printStackTrace();
            Log.info(ex);
        }
        if (n != 1) {
            throw new DuplicateTransactionIDException();
        }
    }

    public void delete(String id) throws TransactionNotFoundException, InvalidTransactionIDFormatException {

        if (id == null) {
            throw new IllegalArgumentException();
        } 

        String sql = "DELETE FROM transactions WHERE id = '" + id + "'";

        int n = 0;
        try {
            conn = DatabaseManager.getConnection();
            statement = conn.createStatement();
            n = statement.executeUpdate(sql);
            Log.info("DELETE:" + n);
        } catch (SQLException ex) {
            ex.printStackTrace();
        }

        if (n < 1) {
            throw new TransactionNotFoundException();
        }

    }

    public Transaction[] getTransactionHistoryByAccount(String account) throws TransactionNotFoundException {
        if (account == null) {
            throw new IllegalArgumentException();
        }

        String query = "SELECT * FROM transactions WHERE (buyerid = '" + account + "' OR sellerid = '" + account + "')";
        ResultSet result = null;

        try {
            conn = DatabaseManager.getConnection();
            statement = conn.createStatement();
            //Log.info(query);
            result = statement.executeQuery(query);
        } catch (Exception ex) {
        }

        Vector v = new Vector();

        int c = 0;
        try {
            while (result.next()) {
                Transaction transaction = get(result.getString("id"));
                v.addElement(transaction);
                c++;
            }
        } catch (Exception ex) {
            throw new TransactionNotFoundException();
        }

        Transaction[] transactionList = new Transaction[v.size()];
        for (int i = 0; i < v.size(); i++) {
            transactionList[i] = (Transaction) v.get(i);
        }

        return transactionList;

    }

    public void close() {
        //try {
            //conn.close();
        //} catch (SQLException ex) {
        //    ex.printStackTrace();
        //}
    }

    public int count() {
        int r = 0;
        Transaction[] b = getAll();
        return b.length;
    }

    

}
